﻿module StyledElements

open Dom
open StyleSheets
open CssTypes
open ComputedStyle
open RenderingContext
open Matcher


type IStyledNode =
    abstract member computedStyle : unit -> ComputedStyle
    abstract member element : Element

type IStyledText =
    inherit IStyledNode
    abstract member nodeValue : string

type IStyledElement =
    inherit IStyledNode
    abstract member childNodes : IStyledNode list
    
type IReplacedElement =
    (* A replaced element (e.g. IMG) handles its own rendering and has an intrinsic size  *)
    inherit IStyledNode
    abstract member intrinsicSize : unit -> int*int
    abstract member render : RenderingContext -> unit

[<AbstractClass>]
type StyledElement(doc, tagName:string, attributes:Map<string,string>) =
    inherit Element(doc, tagName, attributes) 
    let mutable _computedStyle : Option<ComputedStyle> = None

    member this.cascadedStyle() =
        let matcher (selector:Selector) =
            matchSelector selector this
        let cascaded = getCascadedStyle (this.ownerDocument.stylesheets.rules) matcher
        // update with style-attribute if it exists
        match this.attributes.TryFind "style" with
        | None -> cascaded
        | Some str ->
            cascaded.updateStyles (readStyle str)


    member this.computedStyle() =
        if _computedStyle.IsNone then            
            let cs = ComputedStyle(this.cascadedStyle().map, (fun ()->
                    match this.parentElement with 
                    | Some elem -> Some((elem :?> StyledElement).computedStyle())
                    | None -> None))
            _computedStyle <- Some cs
        _computedStyle.Value

    interface IStyledElement with
        member this.computedStyle() = this.computedStyle() 
        member this.childNodes 
            with get() = 
                this.childNodes |> Seq.cast<IStyledNode> |> Seq.toList
        member this.element with get() = this :> Element


and StyledText(doc, text) =
    inherit Text(doc, text)

    interface IStyledText with
        member this.computedStyle() = (this.parentElement.Value :?> StyledElement).computedStyle() 
        member this.nodeValue with get() = this.nodeValue 
        member this.element with get() = this.parentElement.Value
    

